home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume23 / abc / part01 next >
Encoding:
Internet Message Format  |  1991-01-08  |  53.3 KB

  1. Subject:  v23i080:  ABC interactive programming environment, Part01/25
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 299a11e2 5a45f603 a955a579 1da3cc71
  5.  
  6. Submitted-by: Steven Pemberton <steven@cwi.nl>
  7. Posting-number: Volume 23, Issue 80
  8. Archive-name: abc/part01
  9.  
  10. This is a posting of an implementation of ABC, a new interactive
  11. programming language. Versions for Unix, the Atari ST, the Macintosh,
  12. and MS-DOS are being posted this week to the net.
  13.  
  14. ABC is an imperative language originally designed as a replacement for
  15. BASIC: interactive, very easy to learn, but structured, high-level,
  16. and easy to use.
  17.  
  18. It is suitable for general everyday programming, the sort of
  19. programming that you would use BASIC, Pascal, or AWK for. It is not a
  20. systems-programming language. It is an excellent teaching language,
  21. and because it is interactive, excellent for prototyping. It is much
  22. faster than 'bc' for doing quick calculations.
  23.  
  24. ABC programs are typically very compact, around a quarter to a fifth
  25. the size of the equivalent Pascal or C program. However, this is not
  26. at the cost of readability, on the contrary in fact.
  27.  
  28. ABC is simple to learn due to the small number of types in the
  29. language (five). If you already know Pascal or something similar you
  30. can learn the whole language in an hour or so.  It is easy to use
  31. because the data-types are very high-level.
  32.  
  33. Fuller documentation, including examples, is in the file abcintro.doc
  34.  
  35.  
  36. #! /bin/sh
  37. # This is a shell archive.  Remove anything before this line, then feed it
  38. # into a shell via "sh file" or similar.  To overwrite existing files,
  39. # type "sh file -c".
  40. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  41. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  42. # Contents:  MANIFEST abc abc/b abc/bed abc/bhdrs abc/bint1 abc/bint2
  43. #   abc/bint3 abc/bint3/i3sou.c abc/bio abc/boot abc/btr abc/doc
  44. #   abc/ehdrs abc/ex abc/ex/generate abc/ex/hanoi abc/ex/pi abc/ex/try
  45. #   abc/ex/xref abc/ihdrs abc/keys abc/lin abc/lin/i1obj.c abc/scripts
  46. #   abc/stc abc/tc abc/uhdrs abc/ukeys abc/unix
  47. # Wrapped by rsalz@litchi.bbn.com on Mon Dec 17 13:27:50 1990
  48. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  49. echo If this archive is complete, you will see the following message:
  50. echo '          "shar: End of archive 1 (of 25)."'
  51. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  52.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  53. else
  54.   echo shar: Extracting \"'MANIFEST'\" \(8839 characters\)
  55.   sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  56. X   File Name        Archive #    Description
  57. X----------------------------------------------------------
  58. XMANIFEST                   1    
  59. Xabc                        1    
  60. Xabc/Makefile.unix         12    
  61. Xabc/Problems              11    
  62. Xabc/README                23    
  63. Xabc/README2               23    
  64. Xabc/Setup                  9    
  65. Xabc/abc.1                  4    
  66. Xabc/abc.hlp                7    
  67. Xabc/abc.msg               10    
  68. Xabc/b                      1    
  69. Xabc/b/DEP                 24    
  70. Xabc/b/MF                  25    
  71. Xabc/b/b1file.c            23    
  72. Xabc/b/b1grab.c            21    
  73. Xabc/b/b1memo.c            22    
  74. Xabc/b/b1mess.c            22    
  75. Xabc/b/b1outp.c            21    
  76. Xabc/b/getopt.c            23    
  77. Xabc/bed                    1    
  78. Xabc/bed/DEP               15    
  79. Xabc/bed/MF                25    
  80. Xabc/bed/e1cell.c          18    
  81. Xabc/bed/e1code.c          24    
  82. Xabc/bed/e1comm.c          21    
  83. Xabc/bed/e1deco.c          11    
  84. Xabc/bed/e1edit.c          19    
  85. Xabc/bed/e1edoc.c          10    
  86. Xabc/bed/e1erro.c          20    
  87. Xabc/bed/e1eval.c          20    
  88. Xabc/bed/e1getc.c           8    
  89. Xabc/bed/e1goto.c          19    
  90. Xabc/bed/e1gram.c          18    
  91. Xabc/bed/e1ins2.c          18    
  92. Xabc/bed/e1inse.c          17    
  93. Xabc/bed/e1lexi.c          24    
  94. Xabc/bed/e1line.c          20    
  95. Xabc/bed/e1move.c          17    
  96. Xabc/bed/e1node.c          14    
  97. Xabc/bed/e1outp.c          17    
  98. Xabc/bed/e1que1.c          13    
  99. Xabc/bed/e1que2.c           6    
  100. Xabc/bed/e1save.c          23    
  101. Xabc/bed/e1scrn.c          14    
  102. Xabc/bed/e1spos.c          21    
  103. Xabc/bed/e1sugg.c           9    
  104. Xabc/bed/e1supr.c           8    
  105. Xabc/bed/e1tabl.c           4    
  106. Xabc/bed/e1term.c          25    
  107. Xabc/bed/e1wide.c          19    
  108. Xabc/bhdrs                  1    
  109. Xabc/bhdrs/b.h             22    
  110. Xabc/bhdrs/b0lan.h         22    
  111. Xabc/bhdrs/bcom.h          25    
  112. Xabc/bhdrs/bedi.h          24    
  113. Xabc/bhdrs/bfil.h          24    
  114. Xabc/bhdrs/bgfx.h          25    
  115. Xabc/bhdrs/bmem.h          25    
  116. Xabc/bhdrs/bobj.h          21    
  117. Xabc/bhdrs/getopt.h        25    
  118. Xabc/bhdrs/release.h       25    
  119. Xabc/bint1                  1    
  120. Xabc/bint1/DEP             13    
  121. Xabc/bint1/MF              25    
  122. Xabc/bint1/i1fun.c         10    
  123. Xabc/bint1/i1nua.c         14    
  124. Xabc/bint1/i1nuc.c         16    
  125. Xabc/bint1/i1nug.c         18    
  126. Xabc/bint1/i1nui.c         17    
  127. Xabc/bint1/i1num.c          2    
  128. Xabc/bint1/i1nur.c         20    
  129. Xabc/bint1/i1nut.c         22    
  130. Xabc/bint2                  1    
  131. Xabc/bint2/DEP             22    
  132. Xabc/bint2/MF              25    
  133. Xabc/bint2/i2ana.c         16    
  134. Xabc/bint2/i2cmd.c         15    
  135. Xabc/bint2/i2dis.c         19    
  136. Xabc/bint2/i2exp.c          9    
  137. Xabc/bint2/i2fix.c         21    
  138. Xabc/bint2/i2gen.c          7    
  139. Xabc/bint2/i2syn.c         11    
  140. Xabc/bint2/i2tar.c         24    
  141. Xabc/bint2/i2tes.c         21    
  142. Xabc/bint2/i2uni.c         15    
  143. Xabc/bint3                  1    
  144. Xabc/bint3/MF              25    
  145. Xabc/bint3/i3bws.c          7    
  146. Xabc/bint3/i3com.c         22    
  147. Xabc/bint3/i3env.c         21    
  148. Xabc/bint3/i3err.c         16    
  149. Xabc/bint3/i3fil.c         20    
  150. Xabc/bint3/i3fpr.c         18    
  151. Xabc/bint3/i3gfx.c         17    
  152. Xabc/bint3/i3imm.c         22    
  153. Xabc/bint3/i3in2.c         22    
  154. Xabc/bint3/i3ini.c         22    
  155. Xabc/bint3/i3int.c         15    
  156. Xabc/bint3/i3loc.c         13    
  157. Xabc/bint3/i3scr.c         13    
  158. Xabc/bint3/i3sou.c          1    
  159. Xabc/bint3/i3sta.c          8    
  160. Xabc/bint3/i3typ.c         19    
  161. Xabc/bio                    1    
  162. Xabc/bio/DEP                5    
  163. Xabc/bio/MF                25    
  164. Xabc/bio/i4bio.c           24    
  165. Xabc/bio/i4bio.h           24    
  166. Xabc/bio/i4fil.c           20    
  167. Xabc/bio/i4grp.c           23    
  168. Xabc/bio/i4inp.c           25    
  169. Xabc/bio/i4lis.c           25    
  170. Xabc/bio/i4out.c           24    
  171. Xabc/bio/i4rec.c           19    
  172. Xabc/boot                   1    
  173. Xabc/boot/Makefile         20    
  174. Xabc/boot/Makefile.bsd     23    
  175. Xabc/boot/README           23    
  176. Xabc/boot/alloc.c          25    
  177. Xabc/boot/comp.c           21    
  178. Xabc/boot/dump.c            6    
  179. Xabc/boot/grammar.abc      12    
  180. Xabc/boot/lang.h           24    
  181. Xabc/boot/main.h           22    
  182. Xabc/boot/read.c           11    
  183. Xabc/btr                    1    
  184. Xabc/btr/DEP               23    
  185. Xabc/btr/MF                25    
  186. Xabc/btr/e1etex.c          24    
  187. Xabc/btr/etex.h            25    
  188. Xabc/btr/i1btr.c           21    
  189. Xabc/btr/i1btr.h           19    
  190. Xabc/btr/i1lta.c            5    
  191. Xabc/btr/i1obj.c           14    
  192. Xabc/btr/i1tex.c           12    
  193. Xabc/btr/i1tlt.c           14    
  194. Xabc/btr/i1tlt.h           25    
  195. Xabc/ch_all                24    
  196. Xabc/ch_clean              25    
  197. Xabc/ch_config             10    
  198. Xabc/ch_depend             25    
  199. Xabc/ch_install            24    
  200. Xabc/ch_makefiles          25    
  201. Xabc/ch_messages           24    
  202. Xabc/doc                    1    
  203. Xabc/doc/ABCproject        23    
  204. Xabc/doc/BugReport         24    
  205. Xabc/doc/Structure         24    
  206. Xabc/doc/abcintro.doc      16    
  207. Xabc/ehdrs                  1    
  208. Xabc/ehdrs/cell.h          24    
  209. Xabc/ehdrs/code.h          25    
  210. Xabc/ehdrs/erro.h          24    
  211. Xabc/ehdrs/getc.h          23    
  212. Xabc/ehdrs/gram.h          25    
  213. Xabc/ehdrs/keys.h          22    
  214. Xabc/ehdrs/node.h          22    
  215. Xabc/ehdrs/queu.h          25    
  216. Xabc/ehdrs/supr.h          23    
  217. Xabc/ehdrs/tabl.h          15    
  218. Xabc/ehdrs/trm.h           24    
  219. Xabc/ex                     1    
  220. Xabc/ex/DoExamples         25    
  221. Xabc/ex/README             24    
  222. Xabc/ex/TryEditor          24    
  223. Xabc/ex/generate            1    
  224. Xabc/ex/generate.in        25    
  225. Xabc/ex/generate.out       24    
  226. Xabc/ex/generate/analyze.cmd 25    
  227. Xabc/ex/generate/enders.cts 25    
  228. Xabc/ex/generate/fill.cmd  25    
  229. Xabc/ex/generate/follower.cts 23    
  230. Xabc/ex/generate/generate.cmd 25    
  231. Xabc/ex/generate/perm.abc  25    
  232. Xabc/ex/generate/start.cmd 25    
  233. Xabc/ex/generate/starters.cts 25    
  234. Xabc/ex/generate/suggest.abc 25    
  235. Xabc/ex/hanoi               1    
  236. Xabc/ex/hanoi.in           25    
  237. Xabc/ex/hanoi.out          25    
  238. Xabc/ex/hanoi/hanoi.cmd    25    
  239. Xabc/ex/hanoi/perm.abc     25    
  240. Xabc/ex/hanoi/suggest.abc   2    
  241. Xabc/ex/pi                  1    
  242. Xabc/ex/pi.in              25    
  243. Xabc/ex/pi.out             25    
  244. Xabc/ex/pi/perm.abc        25    
  245. Xabc/ex/pi/pi.cmd          25    
  246. Xabc/ex/pi/suggest.abc     25    
  247. Xabc/ex/try                 1    
  248. Xabc/ex/try/analyze.cmd    25    
  249. Xabc/ex/try/enders.cts     25    
  250. Xabc/ex/try/fill.cmd       25    
  251. Xabc/ex/try/follower.cts   23    
  252. Xabc/ex/try/generate.cmd   25    
  253. Xabc/ex/try/perm.abc       25    
  254. Xabc/ex/try/position.abc    7    
  255. Xabc/ex/try/start.cmd      25    
  256. Xabc/ex/try/starters.cts   25    
  257. Xabc/ex/try/suggest.abc    25    
  258. Xabc/ex/wsgroup.abc         4    
  259. Xabc/ex/xref                1    
  260. Xabc/ex/xref.in            25    
  261. Xabc/ex/xref.out           25    
  262. Xabc/ex/xref/alphabet.mpd  25    
  263. Xabc/ex/xref/output.cmd    25    
  264. Xabc/ex/xref/perm.abc      25    
  265. Xabc/ex/xref/save.cmd      25    
  266. Xabc/ex/xref/suggest.abc   25    
  267. Xabc/ex/xref/text.cts      25    
  268. Xabc/ex/xref/words.mfd     25    
  269. Xabc/ex/xref/xref.cmd      25    
  270. Xabc/ex/xref/xtab.cts      25    
  271. Xabc/ihdrs                  1    
  272. Xabc/ihdrs/i0err.h         23    
  273. Xabc/ihdrs/i1num.h         20    
  274. Xabc/ihdrs/i2exp.h         24    
  275. Xabc/ihdrs/i2gen.h         25    
  276. Xabc/ihdrs/i2nod.h         18    
  277. Xabc/ihdrs/i2par.h         16    
  278. Xabc/ihdrs/i3bws.h         25    
  279. Xabc/ihdrs/i3env.h         24    
  280. Xabc/ihdrs/i3in2.h         25    
  281. Xabc/ihdrs/i3int.h         24    
  282. Xabc/ihdrs/i3scr.h         25    
  283. Xabc/ihdrs/i3sou.h         23    
  284. Xabc/ihdrs/i3sta.h         25    
  285. Xabc/ihdrs/i3typ.h         25    
  286. Xabc/keys                   1    
  287. Xabc/keys/DEP              22    
  288. Xabc/keys/Makefile         23    
  289. Xabc/keys/keydef.c          3    
  290. Xabc/keys/keydef.h         23    
  291. Xabc/keys/keyhlp.c         20    
  292. Xabc/lin                    1    
  293. Xabc/lin/etex.h            25    
  294. Xabc/lin/i1lta.c           16    
  295. Xabc/lin/i1obj.c            1    
  296. Xabc/lin/i1tex.c           21    
  297. Xabc/lin/i1tlt.c           12    
  298. Xabc/lin/i1tlt.h           17    
  299. Xabc/mkconfig.c            13    
  300. Xabc/scripts                1    
  301. Xabc/scripts/Change        24    
  302. Xabc/scripts/Collect       24    
  303. Xabc/scripts/mkdep.gen      9    
  304. Xabc/stc                    1    
  305. Xabc/stc/DEP               24    
  306. Xabc/stc/MF                25    
  307. Xabc/stc/i2stc.h           22    
  308. Xabc/stc/i2tca.c            3    
  309. Xabc/stc/i2tce.c           17    
  310. Xabc/stc/i2tcp.c           18    
  311. Xabc/stc/i2tcu.c           20    
  312. Xabc/tc                     1    
  313. Xabc/tc/Makefile           24    
  314. Xabc/tc/README             23    
  315. Xabc/tc/tc1.c              25    
  316. Xabc/tc/tc2.c              24    
  317. Xabc/tc/tc3.c              23    
  318. Xabc/tc/termcap             6    
  319. Xabc/tc/termcap.5           5    
  320. Xabc/tc/termcap.c          19    
  321. Xabc/tc/tgoto.c            21    
  322. Xabc/tc/tputs.c            22    
  323. Xabc/uhdrs                  1    
  324. Xabc/uhdrs/args.h          25    
  325. Xabc/uhdrs/conf.h          24    
  326. Xabc/uhdrs/defs.h          25    
  327. Xabc/uhdrs/dir.h           24    
  328. Xabc/uhdrs/feat.h          23    
  329. Xabc/uhdrs/os.h.gen        23    
  330. Xabc/uhdrs/osconf.h        25    
  331. Xabc/ukeys                  1    
  332. Xabc/ukeys/abckeys_2621    24    
  333. Xabc/ukeys/abckeys_2640b   25    
  334. Xabc/ukeys/abckeys_5620    24    
  335. Xabc/ukeys/abckeys_5620-2  24    
  336. Xabc/ukeys/abckeys_5620-e  24    
  337. Xabc/ukeys/abckeys_924     21    
  338. Xabc/ukeys/abckeys_adm31   24    
  339. Xabc/unix                   1    
  340. Xabc/unix/DEP              23    
  341. Xabc/unix/MF               25    
  342. Xabc/unix/u1dir.c          23    
  343. Xabc/unix/u1edit.c         24    
  344. Xabc/unix/u1file.c         20    
  345. Xabc/unix/u1keys.c         15    
  346. Xabc/unix/u1os.c           24    
  347. Xabc/unix/u1time.c         23    
  348. Xabc/unix/u1trm.c           2    
  349. END_OF_FILE
  350.   if test 8839 -ne `wc -c <'MANIFEST'`; then
  351.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  352.   fi
  353.   # end of 'MANIFEST'
  354. fi
  355. if test ! -d 'abc' ; then
  356.     echo shar: Creating directory \"'abc'\"
  357.     mkdir 'abc'
  358. fi
  359. if test ! -d 'abc/b' ; then
  360.     echo shar: Creating directory \"'abc/b'\"
  361.     mkdir 'abc/b'
  362. fi
  363. if test ! -d 'abc/bed' ; then
  364.     echo shar: Creating directory \"'abc/bed'\"
  365.     mkdir 'abc/bed'
  366. fi
  367. if test ! -d 'abc/bhdrs' ; then
  368.     echo shar: Creating directory \"'abc/bhdrs'\"
  369.     mkdir 'abc/bhdrs'
  370. fi
  371. if test ! -d 'abc/bint1' ; then
  372.     echo shar: Creating directory \"'abc/bint1'\"
  373.     mkdir 'abc/bint1'
  374. fi
  375. if test ! -d 'abc/bint2' ; then
  376.     echo shar: Creating directory \"'abc/bint2'\"
  377.     mkdir 'abc/bint2'
  378. fi
  379. if test ! -d 'abc/bint3' ; then
  380.     echo shar: Creating directory \"'abc/bint3'\"
  381.     mkdir 'abc/bint3'
  382. fi
  383. if test -f 'abc/bint3/i3sou.c' -a "${1}" != "-c" ; then 
  384.   echo shar: Will not clobber existing file \"'abc/bint3/i3sou.c'\"
  385. else
  386.   echo shar: Extracting \"'abc/bint3/i3sou.c'\" \(29957 characters\)
  387.   sed "s/^X//" >'abc/bint3/i3sou.c' <<'END_OF_FILE'
  388. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  389. X
  390. X/* Sources: maintaining units and values on external files */
  391. X
  392. X#include "b.h"
  393. X#include "bint.h"
  394. X#include "feat.h"
  395. X#include "bmem.h"
  396. X#include "bobj.h"
  397. X#include "bfil.h"
  398. X#include "i2par.h"
  399. X#include "i2nod.h"
  400. X#include "i3env.h"
  401. X#include "i3scr.h"
  402. X#include "i3in2.h"
  403. X#include "i3sou.h"
  404. X
  405. X#ifdef TYPE_CHECK
  406. Xvalue stc_code();
  407. X#endif
  408. X#ifdef unix
  409. X#define CK_WS_WRITABLE
  410. X#endif
  411. X
  412. XVisible value b_perm= Vnil;
  413. X    /* The table that maps tags to their file names */
  414. XVisible value b_units= Vnil;
  415. X    /* The table that maps tags to their internal repr. */
  416. X
  417. X#define Is_filed(v) (Is_indirect(v))
  418. X
  419. X#define t_exists(name, aa)    (in_env(prmnv->tab, name, aa))
  420. X
  421. XVisible Procedure def_target(name, t) value name, t; {
  422. X    e_replace(t, &prmnv->tab, name);
  423. X}
  424. X
  425. X#define free_target(name)    (e_delete(&prmnv->tab, name))
  426. X
  427. X/************************** UNITS ************************************/
  428. X
  429. X#define Is_funprd(u)        (Is_function(u) || Is_predicate(u))
  430. X#define Is_predefined(u)    (Is_funprd(u) && Funprd(u)->pre != Use)
  431. X
  432. X#define USR_ALL        '1'
  433. X#define USR_PARSED    '2'
  434. X
  435. XHidden Procedure freeunits(which) literal which; {
  436. X    intlet k, len;
  437. X    value vkey, vassoc;
  438. X    
  439. X    len= length(b_units);
  440. X    for (k= len-1; k >= 0; --k) {
  441. X        /* Reverse loop so deletions don't affect the numbering! */
  442. X        vkey= *key(b_units, k);
  443. X        vassoc= *assoc(b_units, k);
  444. X        switch (which) {
  445. X        case USR_ALL:
  446. X            if (!Is_predefined(vassoc)) free_unit(vkey);
  447. X            break;
  448. X        case USR_PARSED:
  449. X            if (!Is_predefined(vassoc) &&
  450. X                    !How_to(vassoc)->unparsed)
  451. X                free_unit(vkey);
  452. X            break;
  453. X        }
  454. X    }
  455. X}
  456. X
  457. XVisible Procedure rem_unit(u) parsetree u; {
  458. X    value pname= get_pname(u);
  459. X    free_unit(pname);
  460. X    release(pname);
  461. X}
  462. X
  463. X/********************************************************************** */
  464. X
  465. XVisible value permkey(name, type) value name; literal type; {
  466. X    char t[2];
  467. X    value v, w;
  468. X    
  469. X    if (!Valid(name))
  470. X        return Vnil;
  471. X    t[0]= type; t[1]= '\0';
  472. X    w= mk_text(t);
  473. X    v= concat(w, name); release(w);
  474. X    return v;
  475. X}
  476. X
  477. XVisible string lastunitname() {
  478. X    value *aa;
  479. X    
  480. X    if (p_exists(last_unit, &aa))
  481. X        return sstrval(Permname(*aa));
  482. X    return NULL;
  483. X}
  484. X
  485. X#define CANTGETFNAME    MESS(4000, "cannot create file name for %s")
  486. X
  487. XHidden value get_ufname(pname, silently) value pname; bool silently; {
  488. X    value fname;
  489. X    value *aa;
  490. X    
  491. X    if (p_exists(pname, &aa))
  492. X        fname= copy(*aa);
  493. X    else {
  494. X        value name= Permname(pname);
  495. X        literal type= Permtype(pname);
  496. X        
  497. X        fname= new_fname(name, type);
  498. X        if (Valid(fname))
  499. X            def_perm(pname, fname);
  500. X        else if (!silently)
  501. X            interrV(CANTGETFNAME, name);
  502. X        release(name);
  503. X    }
  504. X    return fname;
  505. X}
  506. X
  507. XHidden bool p_version(name, type, pname) value name, *pname; literal type; {
  508. X    value *aa;
  509. X    *pname= permkey(name, type);
  510. X    if (p_exists(*pname, &aa)) return Yes;
  511. X    release(*pname); *pname= Vnil;
  512. X    return No;
  513. X}
  514. X
  515. XHidden bool u_version(name, type, pname) value name, *pname; literal type; {
  516. X    value *aa;
  517. X    *pname= permkey(name, type);
  518. X    if (u_exists(*pname, &aa)) return Yes;
  519. X    release(*pname); *pname= Vnil;
  520. X    return No;
  521. X}
  522. X
  523. XHidden bool tar_version(name, pname) value name, *pname; {
  524. X    value *aa;
  525. X    if (p_version(name, Tar, pname))
  526. X        return Yes;
  527. X    else if (t_exists(name, &aa)) {
  528. X        *pname= permkey(name, Tar);
  529. X        return Yes;
  530. X    }
  531. X    else return No;
  532. X}
  533. X
  534. XHidden Procedure del_perm(pname) value pname; {
  535. X    value *aa;
  536. X    if (p_exists(pname, &aa)) {
  537. X        f_delete(*aa);
  538. X        idelpos(*aa);    /* delete file from positions file */
  539. X        free_perm(pname);
  540. X    }
  541. X}
  542. X
  543. X/***********************************************************************/
  544. X
  545. XHidden bool is_loaded(pname, aa) value pname, **aa; {
  546. X    value u= Vnil, npname= Vnil, *a, get_unit();
  547. X    if (u_exists(pname, &a)) {
  548. X        if (Is_predefined(*a) && p_exists(pname, aa)) {
  549. X            /* loading userdefined over predefined */;
  550. X        }
  551. X        else {
  552. X            *aa= a; 
  553. X            return Yes; /* already loaded */
  554. X        }
  555. X    }
  556. X    else if (!p_exists(pname, aa)) {
  557. X        return No;
  558. X    }
  559. X    ifile= fopen(strval(**aa), "r");
  560. X    if (ifile == NULL) {
  561. X        vs_ifile();
  562. X        return No;
  563. X    }
  564. X    Eof= No;
  565. X    first_ilev();
  566. X    u= get_unit(&npname, Yes, No);
  567. X    if (still_ok) def_unit(npname, u);
  568. X    fclose(ifile);
  569. X    vs_ifile();
  570. X    Eof= No;
  571. X    if (still_ok && !u_exists(pname, aa)) {
  572. X        value name= Permname(pname);; 
  573. X        release(uname); uname= copy(pname);
  574. X        curline= How_to(u)->unit; curlino= one;
  575. X        interrV(MESS(4001, "filename and how-to name incompatible for %s"), name);
  576. X        release(name);
  577. X    }
  578. X    release(u); release(npname);
  579. X    return still_ok;
  580. X}
  581. X
  582. X/* Does the unit exist without faults? */
  583. X
  584. XVisible bool is_unit(name, type, aa) value name, **aa; literal type; {
  585. X    value pname;
  586. X    context c; bool is;
  587. X    sv_context(&c);
  588. X    cntxt= In_unit;
  589. X    pname= permkey(name, type);
  590. X    is= is_loaded(pname, aa);
  591. X    release(pname);
  592. X    set_context(&c);
  593. X    return is;
  594. X}
  595. X
  596. X/***********************************************************************/
  597. X
  598. X#define CANT_WRITE    MESS(4002, "cannot create file %s; need write permission in directory")
  599. X
  600. X#define CANT_READ    MESS(4003, "unable to find file")
  601. X
  602. XHidden Procedure u_name_type(v, name, type) parsetree v; value *name;
  603. X        literal *type; {
  604. X    intlet adic;
  605. X    switch (Nodetype(v)) {
  606. X        case HOW_TO:    *type= Cmd; break;
  607. X        case YIELD:    adic= intval(*Branch(v, FPR_ADICITY));
  608. X                *type= adic==0 ? Zfd : adic==1 ? Mfd : Dfd;
  609. X                break;
  610. X        case TEST:    adic= intval(*Branch(v, FPR_ADICITY));
  611. X                *type= adic==0 ? Zpd : adic==1 ? Mpd : Dpd;
  612. X                break;
  613. X        default:    syserr(MESS(4004, "wrong nodetype of how-to"));
  614. X    }
  615. X    *name= copy(*Branch(v, UNIT_NAME));
  616. X}
  617. X
  618. XHidden value get_unit(pname, filed, editing) value *pname; bool filed, editing;
  619. X{
  620. X    value name; literal type;
  621. X    parsetree u= unit(No, editing);
  622. X    if (u == NilTree)
  623. X        return Vnil;
  624. X    u_name_type(u, &name, &type);
  625. X    *pname= permkey(name, type);
  626. X    release(name);
  627. X    switch (Nodetype(u)) {
  628. X        case HOW_TO:    return mk_how(u, filed);
  629. X        case YIELD:    return mk_fun(type, Use, u, filed);
  630. X        case TEST:    return mk_prd(type, Use, u, filed);
  631. X        default:    return Vnil; /* Keep lint happy */
  632. X    }
  633. X}
  634. X
  635. XVisible value get_pname(v) parsetree v; {
  636. X    value pname, name; literal type;
  637. X    u_name_type(v, &name, &type);
  638. X    pname= permkey(name, type);
  639. X    release(name);
  640. X    return pname;
  641. X}
  642. X
  643. XHidden Procedure get_heading(h, pname) parsetree *h; value *pname; {
  644. X    *h= unit(Yes, No);
  645. X    *pname= still_ok ? get_pname(*h) : Vnil;
  646. X}
  647. X
  648. X/********************************************************************** */
  649. X
  650. X/* Check for certain types of name conflicts.
  651. X   The checks made are:
  652. X   - unit with the same name
  653. X   - function and predicate with the same name (and different or same
  654. X     adicity)
  655. X   - function or predicate with the same name as a target
  656. X   - zeroadic and monadic unit with the same name
  657. X   - zeroadic and dyadic unit with the same name.
  658. X*/
  659. X
  660. X#define CR_EXIST    MESS(4005, "there is already a how-to with this name")
  661. X
  662. X#define CR_TAR        MESS(4006, "there is already a permanent location with this name")
  663. X
  664. X#define ED_EXIST    MESS(4007, "*** the how-to name is already in use;\n*** should the old how-to be discarded?\n*** (if not you have to change the how-to name)\n")
  665. X
  666. X#define ED_TAR        MESS(4008, "*** the how-to name is already in use for a permanent location;\n*** should that location be deleted?\n*** (if not you have to change the how-to name)\n")
  667. X
  668. X/* name_conflict() is called if a unit is created (HOW TO ? : command) */
  669. X
  670. XHidden bool name_conflict(pname) value pname; {
  671. X    value npname;
  672. X    if (smash(pname, &npname)) {
  673. X        interr(Permtype(npname) == Tar ? CR_TAR : CR_EXIST);
  674. X        if (Permtype(pname) != Tar)
  675. X            def_perm(last_unit, npname);
  676. X        release(npname);
  677. X        return Yes;
  678. X    }
  679. X    return No;
  680. X}
  681. X
  682. X/* name_clash() is called if a unit is edited through the ':' command */
  683. X
  684. XHidden bool name_clash(pname) value pname; {
  685. X    value npname;
  686. X    
  687. X    if (!Valid(pname))
  688. X        return No;
  689. X    while (smash(pname, &npname)) {
  690. X        if (!do_discard(npname)) {
  691. X            release(npname);
  692. X            return Yes;
  693. X        }
  694. X        /* continue: there can be both a monadic and a    */
  695. X        /*          dyadic version             */
  696. X        release(npname); npname= Vnil;
  697. X    }
  698. X    return No;
  699. X}
  700. X
  701. XHidden bool do_discard(pname) value pname; {
  702. X    bool istarg= Permtype(pname) == Tar;
  703. X    
  704. X    if (is_intended(istarg ? ED_TAR : ED_EXIST)) {
  705. X        if (istarg) {
  706. X            value name= Permname(pname);
  707. X            del_target(name);
  708. X            release(name);
  709. X        }
  710. X        else {
  711. X            free_unit(pname);
  712. X            del_perm(pname);
  713. X        }
  714. X        return Yes;
  715. X    }
  716. X    return No;
  717. X}
  718. X
  719. XHidden bool smash(pname, npname) value pname, *npname; {
  720. X    value name, *aa;
  721. X    literal u_type, v_type;
  722. X    bool sm;
  723. X
  724. X    if (p_exists(pname, &aa)) {
  725. X        *npname= copy(pname);
  726. X        return Yes;
  727. X    }
  728. X    u_type= Permtype(pname);
  729. X    if (u_type == Cmd) {
  730. X        *npname= Vnil;
  731. X        return No;
  732. X    }
  733. X    name= Permname(pname);
  734. X    sm= p_version(name, Zfd, npname) ||
  735. X        p_version(name, Mfd, npname) ||
  736. X        p_version(name, Dfd, npname) ||
  737. X        p_version(name, Zpd, npname) ||
  738. X        p_version(name, Mpd, npname) ||
  739. X        p_version(name, Dpd, npname) ||
  740. X        tar_version(name, npname);
  741. X    release(name);
  742. X    if (!sm) {
  743. X        release(*npname); *npname= Vnil;
  744. X        return No;
  745. X    }
  746. X    v_type= Permtype(*npname);
  747. X    switch (u_type) {
  748. X        case Mfd: sm= v_type != Dfd; break;
  749. X        case Dfd: sm= v_type != Mfd; break;
  750. X        case Mpd: sm= v_type != Dpd; break;
  751. X        case Dpd: sm= v_type != Mpd; break;
  752. X        default: sm= Yes; break;
  753. X    }
  754. X    if (!sm) {
  755. X        release(*npname); *npname= Vnil;
  756. X        return No;
  757. X    }
  758. X    return Yes;
  759. X}
  760. X
  761. X/***********************************************************************/
  762. X
  763. X/* Create a unit via the editor or from the input stream. */
  764. X
  765. XVisible Procedure create_unit() {
  766. X    value pname= Vnil; parsetree heading= NilTree;
  767. X    if (!interactive) {
  768. X        value v= get_unit(&pname, No, No);
  769. X        if (still_ok) def_unit(pname, v);
  770. X        release(v); release(pname);
  771. X        return;
  772. X    }
  773. X    get_heading(&heading, &pname);
  774. X    curline= heading; curlino= one; /* For all error messages */
  775. X    if (still_ok && !name_conflict(pname)) {
  776. X        value fname= get_ufname(pname, No);
  777. X
  778. X        if (Valid(fname)) {
  779. X            FILE *fp= fopen(strval(fname), "w");
  780. X            if (fp == NULL)
  781. X                interrV(CANT_WRITE, fname);
  782. X            else {
  783. X                txptr tp= fcol();
  784. X                do { fputc(Char(tp), fp); }
  785. X                while (Char(tp++) != '\n');
  786. X                fputc('\n', fp);
  787. X                f_close(fp);
  788. X                ed_unit(&pname, &fname, Yes);
  789. X            }
  790. X        }
  791. X        release(fname);
  792. X    }
  793. X    release(pname); release(heading);
  794. X}
  795. X
  796. X
  797. X/***********************************************************************/
  798. X
  799. X/* Edit a unit. The name of the unit is either given, or is defaulted
  800. X   to the last unit edited or the last unit that gave an error, whichever
  801. X   was most recent.
  802. X   It is possible for the user to mess things up with the w command, for
  803. X   instance, but this is not checked. It is allowed to rename the unit though,
  804. X   or delete it completely. If the file is empty, the unit is disposed of.
  805. X   Otherwise, the name and adicity are determined and if these have changed,
  806. X   the new unit is written out to a new file, and the original deleted.
  807. X   Thus the original is not saved.
  808. X
  809. X   The function edit_unit parses the command line and does some
  810. X   high-level bookkeeping; ed_unit does the lower-level bookkeeping;
  811. X   f_edit is called to pass control to the editor and wait till it
  812. X   finishes its job.  Note that the editor reads the unit from the file
  813. X   and writes it back (if changed); there is no sharing of data
  814. X   structures such as parse trees in this version of the system.
  815. X
  816. X   Renaming, deleting, or changing the adicity of a test or yield
  817. X   unfortunately requires all other units to be thrown away internally
  818. X   (by freeunits), since the unit parse trees may be wrong. For instance,
  819. X   consider the effect on the following of making a formerly monadic
  820. X   function f, into a zeroadic function:
  821. X    WRITE f root 2
  822. X*/
  823. X
  824. X#define CANT_EDIT    MESS(4009, "I find nothing editible here")
  825. X
  826. XVisible value last_unit= Vnil;
  827. X
  828. XVisible Procedure edit_unit() {
  829. X    value name= Vnil, pname= Vnil; 
  830. X    value fname, *aa;
  831. X    value which_funprd();
  832. X    char *kw;
  833. X
  834. X    if (Ceol(tx)) {
  835. X        if (!p_exists(last_unit, &aa))
  836. X            parerr(MESS(4010, "no current how-to"));
  837. X        else pname= copy(*aa);
  838. X    }
  839. X    else if (is_cmdname(ceol, &kw)) {
  840. X        name= mk_text(kw);
  841. X        pname= permkey(name, Cmd);
  842. X    }
  843. X    else if (is_tag(&name))
  844. X        pname= which_funprd(name);
  845. X    else
  846. X        parerr(CANT_EDIT);
  847. X
  848. X    if (still_ok && ens_filed(pname, &fname)) {
  849. X        ed_unit(&pname, &fname, No);
  850. X        release(fname);
  851. X    }
  852. X    release(name); release(pname);
  853. X}
  854. X
  855. X#define ED_MONDYA    MESS(4011, "*** do you want to visit the version with %c or %c operands?\n")
  856. X#define ONE_PAR '1'
  857. X#define TWO_PAR '2'
  858. X
  859. XHidden value which_funprd(name) value name; {
  860. X    /* There may be two units with the same name (functions
  861. X       or predicates of different adicity).  Check if this
  862. X       is the case, and if so, ask which one is meant.
  863. X    */
  864. X    value pname, v= Vnil;
  865. X    char qans;
  866. X    
  867. X    if (p_version(name, Zfd, &pname) || p_version(name, Zpd, &pname))
  868. X        return pname;
  869. X    if (p_version(name, Mfd, &pname) || p_version(name, Mpd, &pname)) {
  870. X        if (p_version(name, Dfd, &v) || p_version(name, Dpd, &v)) {
  871. X            qans= q_answer(ED_MONDYA, ONE_PAR, TWO_PAR);
  872. X            if (qans == ONE_PAR) {
  873. X                release(v);
  874. X                return pname;
  875. X            }
  876. X            else if (qans == TWO_PAR) {
  877. X                release(pname);
  878. X                return copy(v);
  879. X            }
  880. X            else {
  881. X                /* interrupted */
  882. X                still_ok = No;
  883. X                return pname;
  884. X            }
  885. X        }
  886. X        else {
  887. X            release(v);
  888. X            return pname;
  889. X        }
  890. X    }
  891. X    if (p_version(name, Dfd, &pname))
  892. X        return pname;
  893. X    if (p_version(name, Dpd, &pname))
  894. X        return pname;
  895. X
  896. X    /* be prepared to find at least one not-filed how-to;
  897. X     * this does not find all of them;
  898. X     * and it doesn't allow any conflicting with already existing ones.
  899. X     */
  900. X    
  901. X    if (u_version(name, Zfd, &pname) ||
  902. X        u_version(name, Mfd, &pname) ||
  903. X        u_version(name, Dfd, &pname) ||
  904. X        u_version(name, Zpd, &pname) ||
  905. X        u_version(name, Mpd, &pname) ||
  906. X        u_version(name, Dpd, &pname)
  907. X    )
  908. X        return pname;
  909. X
  910. X    return permkey(name, Dpd);
  911. X    /* If it doesn't exist, ens_filed will complain. */
  912. X}
  913. X    
  914. X#define NO_U_WRITE    MESS(4012, "*** you have no write permission in this workspace:\n*** you may not change the how-to\n*** do you still want to display the how-to?\n")
  915. X
  916. X/* Edit a unit.  Parameters are the prmnv key and the file name.
  917. X   This is called in response to the ':' command and when a new unit is
  918. X   created (the header of the new unit must already be written to the
  919. X   file).
  920. X   Side effects are many, e.g. on prmnv: the unit may be deleted or
  921. X   renamed.  When renamed, the original unit is lost.
  922. X   The unit is reparsed after editing.  A check is made for illegal
  923. X   name conflicts (e.g., a zeroadic and a monadic unit of the same
  924. X   name), and this is resolved by forcing the user to edit the unit
  925. X   again. In that case the edit is done on a temporary file.
  926. X   The new unit name is kept as the current unit name; when the unit is
  927. X   deleted the current unit name is set to Vnil. */
  928. X
  929. XHidden bool clash;
  930. X
  931. X#define First_edit (!clash)
  932. X
  933. X#ifdef TYPE_CHECK
  934. XHidden value old_typecode= Vnil;
  935. X#define Sametypes(old, new) ((!Valid(old) && !Valid(new)) || \
  936. X        (Valid(old) && Valid(new) && compare(old, new) == 0))
  937. X#endif
  938. X
  939. XHidden Procedure ed_unit(pname, fname, creating) value *pname, *fname;
  940. X        bool creating;
  941. X{
  942. X#ifdef CK_WS_WRITABLE
  943. X    if (!wsp_writable() && !is_intended(NO_U_WRITE)) return;
  944. X#endif
  945. X#ifdef CLEAR_MEM
  946. X    clear_perm();
  947. X        /* To give the editor as much space as possible, remove
  948. X           all parse trees and target values from memory.
  949. X           (targets that have been modified are first written
  950. X           out, of course).
  951. X        */
  952. X#endif
  953. X    clash= No;
  954. X#ifdef TYPE_CHECK
  955. X    old_typecode= stc_code(*pname);
  956. X    if (!creating) del_types();
  957. X#endif
  958. X    do edunit(pname, fname, creating); while (clash);
  959. X#ifdef SAVE_PERM
  960. X    put_perm(b_perm);
  961. X#endif
  962. X#ifdef TYPE_CHECK
  963. X    release(old_typecode);
  964. X#endif
  965. X}
  966. X
  967. XHidden Procedure edunit(p_pname, p_fname, creating) value *p_pname, *p_fname;
  968. X        bool creating; {
  969. X    value pname= *p_pname, fname= *p_fname;
  970. X    value npname= Vnil, u;
  971. X    bool new_def, changed, samehead;
  972. X#ifdef TYPE_CHECK
  973. X    value new_typecode;
  974. X#endif
  975. X
  976. X    release(uname); uname= copy(pname);
  977. X    changed= f_edit(fname, err_line(pname), ':', creating && First_edit)
  978. X         || creating;
  979. X    errlino= 0;
  980. X    if (First_edit && !changed) {
  981. X        /* Remember it as current unit: */
  982. X        def_perm(last_unit, pname);
  983. X#ifdef TYPE_CHECK
  984. X        if (!creating) adjust_types(Yes);
  985. X#endif
  986. X        return;
  987. X    }
  988. X    if (!still_there(fname)) {
  989. X        free_original(pname);
  990. X#ifdef TYPE_CHECK
  991. X        if (!creating) adjust_types(No);
  992. X#endif
  993. X        idelpos(fname);    /* delete file from positions file */
  994. X        free_perm(last_unit);
  995. X        clash= No;
  996. X        return;
  997. X    }
  998. X    first_ilev();
  999. X    u= get_unit(&npname, Yes, Yes);
  1000. X        /* the second Yes means the user may edit the heading;
  1001. X         * therefore no type check now in unit() */
  1002. X    fclose(ifile); vs_ifile(); Eof= No;
  1003. X    
  1004. X    if (First_edit && same_heading(pname, npname, u)) {
  1005. X        new_def= Yes;
  1006. X        samehead= Yes;
  1007. X    }
  1008. X    else {
  1009. X        samehead= No;
  1010. X        free_original(pname);
  1011. X        if (!name_clash(npname) && rnm_file(fname, npname))
  1012. X            clash= No;
  1013. X        else {
  1014. X            /* edit again with npname and temp fname */
  1015. X            release(*p_pname);
  1016. X            *p_pname= copy(npname);
  1017. X            if (First_edit) {
  1018. X                value tfile= mk_text(temp1file);
  1019. X                f_rename(fname, tfile);
  1020. X                imovpos(fname, tfile);
  1021. X                /* move position in positions file */
  1022. X                release(*p_fname);
  1023. X                *p_fname= tfile;
  1024. X            }
  1025. X            clash= Yes;
  1026. X        }
  1027. X        new_def= !clash;
  1028. X    }
  1029. X    if (new_def) {
  1030. X        /* changed heading now def_perm()'ed, so now typecheck */
  1031. X#ifdef TYPE_CHECK
  1032. X        type_check((Is_funprd(u) ? Funprd(u)->unit : How_to(u)->unit));
  1033. X        new_typecode= stc_code(npname);
  1034. X        if (!creating)
  1035. X            adjust_types(samehead &&
  1036. X                     Sametypes(old_typecode, new_typecode));
  1037. X        release(new_typecode);
  1038. X#endif
  1039. X        if (still_ok) def_unit(npname, u);
  1040. X        else free_unit(npname);
  1041. X        def_perm(last_unit, npname);
  1042. X    }
  1043. X    release(npname); release(u);
  1044. X}
  1045. X
  1046. XHidden Procedure free_original(pname) value pname; {
  1047. X    if (First_edit) {
  1048. X        free_unit(pname); 
  1049. X        free_perm(pname);
  1050. X        freeunits(USR_PARSED);
  1051. X    }
  1052. X}
  1053. X
  1054. X#define cmd_unit(pname)    (Permtype(pname) == Cmd)
  1055. X
  1056. XHidden bool same_heading(pname, npname, u_new) value pname, npname, u_new; {
  1057. X    value *aa;
  1058. X    
  1059. X    if (!Valid(u_new) || !Valid(npname))
  1060. X        return No;
  1061. X    else if (compare(pname, npname) != 0)
  1062. X        return No;
  1063. X    else if (!cmd_unit(pname))
  1064. X        return Yes;
  1065. X    else if (!u_exists(pname, &aa))
  1066. X        return Yes;
  1067. X    else {
  1068. X        parsetree old= How_to(*aa)->unit;
  1069. X        parsetree new= How_to(u_new)->unit;
  1070. X        parsetree old_kw, old_fml, old_next;
  1071. X        parsetree new_kw, new_fml, new_next;
  1072. X        
  1073. X        old= *Branch(old, HOW_FORMALS);
  1074. X        new= *Branch(new, HOW_FORMALS);
  1075. X        do {
  1076. X            old_kw= *Branch(old, FML_KEYW);
  1077. X            old_fml= *Branch(old, FML_TAG);
  1078. X            old_next= *Branch(old, FML_NEXT);
  1079. X            new_kw= *Branch(new, FML_KEYW);
  1080. X            new_fml= *Branch(new, FML_TAG);
  1081. X            new_next= *Branch(new, FML_NEXT);
  1082. X            
  1083. X            if (compare(old_kw, new_kw) != 0)
  1084. X                return No;
  1085. X            else if (old_fml == NilTree && new_fml != NilTree)
  1086. X                return No;
  1087. X            else if (old_fml != NilTree && new_fml == NilTree)
  1088. X                return No;
  1089. X            else if (old_next == NilTree && new_next != NilTree)
  1090. X                return No;
  1091. X            else if (old_next != NilTree && new_next == NilTree)
  1092. X                return No;
  1093. X            old= old_next;
  1094. X            new= new_next;
  1095. X        }
  1096. X        while (old != NilTree);
  1097. X        return Yes;
  1098. X    }
  1099. X}
  1100. X
  1101. X#define CANT_GET_FNAME    MESS(4013, "*** cannot create file name;\n*** you have to change the how-to name\n")
  1102. X
  1103. XHidden bool rnm_file(fname, pname) value fname, pname; {
  1104. X    value nfname;
  1105. X    
  1106. X    nfname= (Valid(pname) ? get_ufname(pname, Yes) : Vnil);
  1107. X    
  1108. X    if (Valid(nfname)) {
  1109. X        f_rename(fname, nfname);
  1110. X        imovpos(fname, nfname); /* move position in positions file */
  1111. X        release(nfname);
  1112. X        return Yes;
  1113. X    }
  1114. X    else {
  1115. X        putmess(errfile, CANT_GET_FNAME);
  1116. X        return No;
  1117. X    }
  1118. X}
  1119. X
  1120. X/* Find out if the file exists, and is not empty. Some editors don't
  1121. X   allow a file to be edited to empty, but insist it should be at least
  1122. X   one empty line.  Therefore, a file with one, empty, line is also
  1123. X   considered empty.
  1124. X   As a side effect, if the file is 'still there', ifile is set to it
  1125. X   and it remains open, positioned at the beginning.
  1126. X   (A previous version of this function would leave it positioned after
  1127. X   an initial \n, if there was one; this version just rewinds the file.)
  1128. X   */
  1129. X
  1130. XHidden bool still_there(fname) value fname; {
  1131. X    int k;
  1132. X
  1133. X    ifile= fopen(strval(fname), "r");
  1134. X    if (ifile == NULL) {
  1135. X        vs_ifile();
  1136. X        return No;
  1137. X    } else {
  1138. X        if ((k= getc(ifile)) == EOF ||
  1139. X                (k == '\n' && (k= getc(ifile)) == EOF)) {
  1140. X            fclose(ifile);
  1141. X            f_delete(fname);
  1142. X            vs_ifile();
  1143. X            return No;
  1144. X        }
  1145. X        rewind(ifile);
  1146. X        return Yes;
  1147. X    }
  1148. X}
  1149. X
  1150. X/* Ensure the unit is filed. If the unit was read non-interactively (eg passed
  1151. X   as a parameter to abc), it is only held in store.
  1152. X   Editing it puts it into a file. This is the safest way to copy a unit from
  1153. X   one workspace to another.
  1154. X*/
  1155. X
  1156. X#define NO_HOWTO MESS(4014, "%s isn't a how-to in this workspace")
  1157. X
  1158. XHidden bool ens_filed(pname, fname) value pname, *fname; {
  1159. X    value *aa;
  1160. X    if (p_exists(pname, &aa)) {
  1161. X        *fname= copy(*aa);
  1162. X        return Yes;
  1163. X    } else if (!u_exists(pname, &aa) || How_to(*aa)->unit == NilTree) {
  1164. X        value name= Permname(pname);
  1165. X        pprerrV(NO_HOWTO, name);
  1166. X        release(name);
  1167. X        return No;
  1168. X    } else {
  1169. X        how *du= How_to(*aa); FILE *fp;
  1170. X        if (du->filed == Yes) {
  1171. X            syserr(MESS(4015, "ens_filed()"));
  1172. X            return No;
  1173. X        }
  1174. X        *fname= get_ufname(pname, No);
  1175. X        if (!Valid(*fname))
  1176. X            return No;
  1177. X        fp= fopen(strval(*fname), "w");
  1178. X        if (!fp) {
  1179. X            interrV(CANT_WRITE, *fname);
  1180. X            release(*fname);
  1181. X            return No;
  1182. X        } else {
  1183. X            display(fp, du->unit, No);
  1184. X            f_close(fp);
  1185. X            du->filed= Yes;
  1186. X            return Yes;
  1187. X        }
  1188. X    }
  1189. X}
  1190. X
  1191. XHidden int err_line(pname) value pname; {
  1192. X    value *aa;
  1193. X    if (!p_exists(last_unit, &aa) || compare(*aa, pname) != 0)
  1194. X        return 0;
  1195. X    else
  1196. X        return errlino;
  1197. X}
  1198. X
  1199. X/************************** VALUES ***************************************/
  1200. X/* The permanent environment in the old format was kept as a single file */
  1201. X/* but this caused slow start ups if the file was big.             */
  1202. X/* Thus the new version stores each permanent target on a separate file, */
  1203. X/* that furthermore is only loaded on demand.                 */
  1204. X/* To achieve this, a directory is kept of the permanent tags and their  */
  1205. X/* file names. Care has to be taken that disaster occurring in         */
  1206. X/* the middle of an update of this directory does the least harm.     */
  1207. X/* Having the directory refer to a non-existent file is considered less  */
  1208. X/* harmful than leaving a file around that can never be accessed, for     */
  1209. X/* instance, so a file is deleted before its directory entry,         */
  1210. X/* and so forth.                             */
  1211. X/*************************************************************************/
  1212. X
  1213. XVisible value errtname= Vnil;
  1214. X
  1215. XHidden Procedure tarfiled(name, v) value name, v; {
  1216. X    value p= mk_indirect(v);
  1217. X    def_target(name, p);
  1218. X    release(p);
  1219. X}
  1220. X
  1221. XVisible value last_target= Vnil; /* last edited target */
  1222. X
  1223. XVisible Procedure del_target(name) value name; {
  1224. X    value pname= permkey(name, Tar);
  1225. X    value *aa;
  1226. X    free_target(name);
  1227. X    del_perm(pname);
  1228. X    if (p_exists(last_target, &aa) && (compare(name, *aa) == 0))
  1229. X        free_perm(last_target);
  1230. X    release(pname);
  1231. X}
  1232. X
  1233. XHidden value get_tfname(name) value name; {
  1234. X    value fname;
  1235. X    value pname= permkey(name, Tar);
  1236. X    value *aa;
  1237. X    
  1238. X    if (p_exists(pname, &aa))
  1239. X        fname= copy(*aa);
  1240. X    else {
  1241. X        fname= new_fname(name, Tar);
  1242. X        if (Valid(fname))
  1243. X            def_perm(pname, fname);
  1244. X        else
  1245. X            interrV(CANTGETFNAME, name);
  1246. X    }
  1247. X    release(pname);
  1248. X    return fname;
  1249. X}
  1250. X
  1251. XVisible Procedure edit_target() {
  1252. X    value name= Vnil;
  1253. X    value fname, *aa;
  1254. X    if (Ceol(tx)) {
  1255. X        if (!p_exists(last_target, &aa))
  1256. X            parerr(MESS(4016, "no current location"));
  1257. X        else
  1258. X            name= copy(*aa);
  1259. X    } else if (!is_tag(&name))
  1260. X        parerr(CANT_EDIT);
  1261. X    if (still_ok && ens_tfiled(name, &fname)) {
  1262. X        ed_target(name, fname);
  1263. X        release(fname);
  1264. X    }
  1265. X    release(name);
  1266. X}
  1267. X
  1268. X#define NO_T_WRITE    MESS(4017, "*** you have no write permission in this workspace:\n*** you may not change the location\n*** do you still want to display the location?\n")
  1269. X
  1270. X/* Edit a target. The value in the target is written to the file,
  1271. X   and then removed from the internal permanent environment so that
  1272. X   if a syntax error occurs when reading the value back, the value is
  1273. X   absent from the internal permanent environment.
  1274. X   Thus when editing the file to correct the syntax error, the
  1275. X   file doesn't get overwritten.
  1276. X   The contents may be completely deleted in which case the target is
  1277. X   deleted. */
  1278. X
  1279. XHidden Procedure ed_target(name, fname) value name, fname; {
  1280. X    value v;
  1281. X
  1282. X#ifdef CK_WS_WRITABLE
  1283. X    if (!wsp_writable() && !is_intended(NO_T_WRITE)) return;
  1284. X#endif
  1285. X#ifdef CLEAR_MEM
  1286. X    clear_perm(); /* To give the editor as much space as possible */
  1287. X#endif
  1288. X    def_perm(last_target, name);
  1289. X    if (!f_edit(fname, 0, '=', No))
  1290. X        /* File is unchanged */
  1291. X        return;
  1292. X    if (!still_there(fname)) {
  1293. X        del_target(name);
  1294. X#ifdef SAVE_PERM
  1295. X        put_perm(b_perm);
  1296. X#endif
  1297. X        return;
  1298. X    }
  1299. X    fclose(ifile); /* Since still_there leaves it open */
  1300. X    /* vs_ifile(); ? */
  1301. X    v= getval(fname, In_edval);
  1302. X    if (still_ok) def_target(name, v);
  1303. X    release(v);
  1304. X}
  1305. X
  1306. X#define NO_TARGET MESS(4018, "%s isn't a location in this workspace")
  1307. X
  1308. XVisible bool ens_tfiled(name, fname) value name, *fname; {
  1309. X    value *aa;
  1310. X    if (!t_exists(name, &aa)) {
  1311. X        pprerrV(NO_TARGET, name);
  1312. X        return No;
  1313. X    } else {
  1314. X        *fname= get_tfname(name);
  1315. X        if (!Valid(*fname))
  1316. X            return No;
  1317. X        if (!Is_filed(*aa)) {
  1318. X            release(errtname); errtname= copy(name);
  1319. X            putval(*fname, *aa, No, In_tarval);
  1320. X            tarfiled(name, *aa);
  1321. X        }
  1322. X        return Yes;
  1323. X    }
  1324. X}
  1325. X
  1326. X/***************************** Values on files ****************************/
  1327. X
  1328. XVisible value getval(fname, ct) value fname; literal ct; {
  1329. X    char *buf; int k; parsetree w, code= NilTree; value v= Vnil;
  1330. X    ifile= fopen(strval(fname), "r");
  1331. X    if (ifile) {
  1332. X        txptr fcol_save= first_col, tx_save= tx; context c;
  1333. X        sv_context(&c);
  1334. X        cntxt= ct;
  1335. X        buf= (char *) getmem((unsigned)(f_size(ifile)+2)*sizeof(char));
  1336. X        first_col= tx= ceol= buf;
  1337. X        while ((k= getc(ifile)) != EOF)
  1338. X            if (k != '\n') *ceol++= k;
  1339. X        *ceol= '\n';
  1340. X        fclose(ifile); vs_ifile();
  1341. X        w= expr(ceol);
  1342. X        if (still_ok) fix_nodes(&w, &code);
  1343. X        curline= w; curlino= one;
  1344. X        v= evalthread(code); 
  1345. X        if (!env_ok(v)) {
  1346. X            release(v);
  1347. X            v= Vnil;
  1348. X        }
  1349. X        curline= Vnil;
  1350. X        release(w);
  1351. X        freemem((ptr) buf);
  1352. X        set_context(&c);
  1353. X        first_col= fcol_save; tx= tx_save;
  1354. X    } else {
  1355. X        interr(CANT_READ);
  1356. X        vs_ifile();
  1357. X    }
  1358. X    return v;
  1359. X}
  1360. X
  1361. XHidden bool env_ok(v) value v; {
  1362. X    if (cntxt == In_prmnv || cntxt == In_wsgroup) {
  1363. X        if (!Is_table(v)) {
  1364. X            interr(MESS(4019, "value is not a table"));
  1365. X            return No;
  1366. X        }
  1367. X        else if (!Is_ELT(v) && !Is_text(*key(v, 0))) {
  1368. X            interr(MESS(4020, "in t[k], k is not a text"));
  1369. X            return No;
  1370. X        }
  1371. X    }
  1372. X    return Yes;
  1373. X}
  1374. X
  1375. XVisible bool permchanges;
  1376. X
  1377. XVisible Procedure initperm() {
  1378. X    if (F_exists(permfile)) {
  1379. X        value fn, name;
  1380. X        intlet k, len;
  1381. X        value v, pname;
  1382. X        
  1383. X        fn= mk_text(permfile);
  1384. X        v= getval(fn, In_prmnv);
  1385. X        release(fn);
  1386. X        if (Valid(v)) {
  1387. X            release(b_perm);
  1388. X            b_perm= v;
  1389. X        }
  1390. X        len= length(b_perm);
  1391. X        for (k= 0; k < len; k++) {
  1392. X            pname= *key(b_perm, k);
  1393. X            if (Permtype(pname) == Tar) {
  1394. X                name= Permname(pname);
  1395. X                tarfiled(name, Vnil);
  1396. X                release(name);
  1397. X            }
  1398. X        }
  1399. X    }
  1400. X    permchanges= No;
  1401. X}
  1402. X
  1403. XVisible Procedure putval(fname, v, silently, ct) value fname, v;
  1404. X        bool silently; literal ct; {
  1405. X    value fn= copy(fname);
  1406. X    FILE *fp;
  1407. X    bool was_ok= still_ok;
  1408. X    context c;
  1409. X
  1410. X    sv_context(&c);
  1411. X    cntxt= ct;
  1412. X    curline= Vnil;
  1413. X    curlino= one;
  1414. X#ifdef unix
  1415. X    release(fn); fn= mk_text(tempfile);
  1416. X#endif
  1417. X    fp= fopen(strval(fn), "w");
  1418. X    if (fp != NULL) {
  1419. X        redirect(fp);
  1420. X        still_ok= Yes;
  1421. X        wri(v, No, No, Yes); newline();
  1422. X        f_close(fp);
  1423. X        redirect(stdout);
  1424. X#ifdef unix
  1425. X        if (still_ok) f_rename(fn, fname);
  1426. X#endif
  1427. X    }
  1428. X    else if (!silently) interrV(CANT_WRITE, fn);
  1429. X    still_ok= was_ok;
  1430. X    release(fn);
  1431. X    set_context(&c);
  1432. X}
  1433. X
  1434. XVisible Procedure endperm() {
  1435. X    static bool active;
  1436. X    bool was_ok= still_ok;
  1437. X    
  1438. X    if (active)
  1439. X        return;
  1440. X    active= Yes;
  1441. X    still_ok= Yes;
  1442. X    put_targs();
  1443. X    put_perm(b_perm);
  1444. X    still_ok= was_ok;
  1445. X    active= No;
  1446. X}
  1447. X
  1448. XHidden Procedure put_targs() {
  1449. X    int k, len;
  1450. X    value v, name;
  1451. X    
  1452. X    len= Valid(prmnv->tab) ? length(prmnv->tab) : 0;
  1453. X    for (k= 0; k < len; k++) {
  1454. X        v= copy(*assoc(prmnv->tab, k));
  1455. X        name= copy(*key(prmnv->tab, k));
  1456. X        if (!Is_filed(v)) {
  1457. X            value fname= get_tfname(name);
  1458. X            if (Valid(fname)) {
  1459. X                release(errtname); errtname= copy(name);
  1460. X                putval(fname, v, Yes, In_tarval);
  1461. X            }
  1462. X            release(fname);
  1463. X        }
  1464. X        tarfiled(name, Vnil);
  1465. X        release(v); release(name);
  1466. X    }
  1467. X}
  1468. X
  1469. XVisible Procedure put_perm(v) value v; {
  1470. X    value fn;
  1471. X    intlet len;
  1472. X    
  1473. X    if (!permchanges || !Valid(v))
  1474. X        return;
  1475. X    fn= mk_text(permfile);
  1476. X    /* Remove the file if the permanent environment is empty */
  1477. X    len= length(v);
  1478. X    if (len == 0)
  1479. X        f_delete(fn);
  1480. X    else
  1481. X        putval(fn, v, Yes, In_prmnv);
  1482. X    release(fn);
  1483. X    permchanges= No;
  1484. X}
  1485. X
  1486. XVisible Procedure clear_perm() {
  1487. X    freeunits(USR_ALL);
  1488. X    endperm();
  1489. X}
  1490. X
  1491. XVisible Procedure initsou() {
  1492. X    release(b_units); b_units= mk_elt();
  1493. X    release(last_unit); last_unit= mk_text(":");
  1494. X    release(last_target); last_target= mk_text("=");
  1495. X    release(b_perm); b_perm= mk_elt();
  1496. X}
  1497. X
  1498. XVisible Procedure endsou() {
  1499. X    if (terminated)
  1500. X        return;    /* hack; to prevent seemingly endless QUIT */
  1501. X    release(b_units); b_units= Vnil;
  1502. X    release(b_perm); b_perm= Vnil;
  1503. X    release(last_unit); last_unit= Vnil;
  1504. X    release(last_target); last_target= Vnil;
  1505. X}
  1506. X
  1507. X/*
  1508. X * lst_uhds() displays the first line of the unit without a possible
  1509. X * present simple command
  1510. X */
  1511. X#define MORE MESS(4021, "Press [SPACE] for more, [RETURN] to exit list")
  1512. Xextern int winheight;
  1513. Xbool ask_for();
  1514. X
  1515. XVisible Procedure lst_uhds() {
  1516. X    intlet k, len;
  1517. X    value pname, *aa;
  1518. X    how *u;
  1519. X    int nprinted= 0;
  1520. X    bool more= Yes;
  1521. X    
  1522. X    len= length(b_perm);
  1523. X    for (k= 0; k<len && still_ok && more; ++k) {
  1524. X        pname= *key(b_perm, k);
  1525. X        if (!Is_text(pname) || Permtype(pname) == Tar) 
  1526. X            continue;
  1527. X        /* reduce disk access: */
  1528. X        if (u_exists(pname, &aa) && !Is_predefined(*aa))
  1529. X            display(stdout, How_to(*aa)->unit, Yes);
  1530. X        else
  1531. X            lst_fileheading(*assoc(b_perm, k));
  1532. X        fflush(stdout);
  1533. X        if (++nprinted >= winheight) {
  1534. X            more= ask_for(MORE);
  1535. X            nprinted= 0;
  1536. X        }
  1537. X    }
  1538. X    /* not interactive units */
  1539. X    len= length(b_units);
  1540. X    for (k= 0; k<len && still_ok && more; ++k) {
  1541. X        u= How_to(*assoc(b_units, k));
  1542. X        if (u -> filed == No && !p_exists(*key(b_units, k), &aa)) {
  1543. X            display(stdout, u -> unit, Yes);
  1544. X            fflush(stdout);
  1545. X            if (++nprinted >= winheight) {
  1546. X                more= ask_for(MORE);
  1547. X                nprinted= 0;
  1548. X            }
  1549. X        }
  1550. X
  1551. X    }
  1552. X}
  1553. X
  1554. XHidden Procedure lst_fileheading(v) value v; {
  1555. X    FILE *fn;
  1556. X    char *line;
  1557. X    char *pcolon, *pc;
  1558. X
  1559. X    if (!Is_text(v))
  1560. X        return;
  1561. X    fn= fopen(strval(v), "r");
  1562. X    if (!fn)
  1563. X        return;
  1564. X    if ((line= f_getline(fn)) != NULL) {
  1565. X        pcolon= strchr(line, C_COLON);
  1566. X        if (pcolon != NULL) {
  1567. X            pc= ++pcolon;
  1568. X            while (Space(*pc)) ++pc;
  1569. X            if (*pc != C_COMMENT && *pc != '\n') {
  1570. X                /* single command after colon;
  1571. X                 * don't show it.
  1572. X                 */
  1573. X                *(pcolon+1)= '\n';
  1574. X                *(pcolon+2)= '\0';
  1575. X            }
  1576. X        }
  1577. X        putstr(stdout, line);
  1578. X        freestr(line);
  1579. X    }
  1580. X    fclose(fn);
  1581. X}
  1582. END_OF_FILE
  1583.   if test 29957 -ne `wc -c <'abc/bint3/i3sou.c'`; then
  1584.     echo shar: \"'abc/bint3/i3sou.c'\" unpacked with wrong size!
  1585.   fi
  1586.   # end of 'abc/bint3/i3sou.c'
  1587. fi
  1588. if test ! -d 'abc/bio' ; then
  1589.     echo shar: Creating directory \"'abc/bio'\"
  1590.     mkdir 'abc/bio'
  1591. fi
  1592. if test ! -d 'abc/boot' ; then
  1593.     echo shar: Creating directory \"'abc/boot'\"
  1594.     mkdir 'abc/boot'
  1595. fi
  1596. if test ! -d 'abc/btr' ; then
  1597.     echo shar: Creating directory \"'abc/btr'\"
  1598.     mkdir 'abc/btr'
  1599. fi
  1600. if test ! -d 'abc/doc' ; then
  1601.     echo shar: Creating directory \"'abc/doc'\"
  1602.     mkdir 'abc/doc'
  1603. fi
  1604. if test ! -d 'abc/ehdrs' ; then
  1605.     echo shar: Creating directory \"'abc/ehdrs'\"
  1606.     mkdir 'abc/ehdrs'
  1607. fi
  1608. if test ! -d 'abc/ex' ; then
  1609.     echo shar: Creating directory \"'abc/ex'\"
  1610.     mkdir 'abc/ex'
  1611. fi
  1612. if test ! -d 'abc/ex/generate' ; then
  1613.     echo shar: Creating directory \"'abc/ex/generate'\"
  1614.     mkdir 'abc/ex/generate'
  1615. fi
  1616. if test ! -d 'abc/ex/hanoi' ; then
  1617.     echo shar: Creating directory \"'abc/ex/hanoi'\"
  1618.     mkdir 'abc/ex/hanoi'
  1619. fi
  1620. if test ! -d 'abc/ex/pi' ; then
  1621.     echo shar: Creating directory \"'abc/ex/pi'\"
  1622.     mkdir 'abc/ex/pi'
  1623. fi
  1624. if test ! -d 'abc/ex/try' ; then
  1625.     echo shar: Creating directory \"'abc/ex/try'\"
  1626.     mkdir 'abc/ex/try'
  1627. fi
  1628. if test ! -d 'abc/ex/xref' ; then
  1629.     echo shar: Creating directory \"'abc/ex/xref'\"
  1630.     mkdir 'abc/ex/xref'
  1631. fi
  1632. if test ! -d 'abc/ihdrs' ; then
  1633.     echo shar: Creating directory \"'abc/ihdrs'\"
  1634.     mkdir 'abc/ihdrs'
  1635. fi
  1636. if test ! -d 'abc/keys' ; then
  1637.     echo shar: Creating directory \"'abc/keys'\"
  1638.     mkdir 'abc/keys'
  1639. fi
  1640. if test ! -d 'abc/lin' ; then
  1641.     echo shar: Creating directory \"'abc/lin'\"
  1642.     mkdir 'abc/lin'
  1643. fi
  1644. if test -f 'abc/lin/i1obj.c' -a "${1}" != "-c" ; then 
  1645.   echo shar: Will not clobber existing file \"'abc/lin/i1obj.c'\"
  1646. else
  1647.   echo shar: Extracting \"'abc/lin/i1obj.c'\" \(7180 characters\)
  1648.   sed "s/^X//" >'abc/lin/i1obj.c' <<'END_OF_FILE'
  1649. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  1650. X
  1651. X/* Generic routines for all values */
  1652. X
  1653. X#include "b.h"
  1654. X#include "bint.h"
  1655. X#include "bmem.h"
  1656. X#include "bobj.h"
  1657. X#include "i1tlt.h"
  1658. X#include "i3typ.h"
  1659. X
  1660. X#define Len (len < 200 ? len : ((len-1)/8+1)*8)
  1661. X
  1662. XVisible unsigned tltsyze(type, len, nptrs) 
  1663. X    literal type;
  1664. X    intlet len;
  1665. X    int *nptrs;
  1666. X{
  1667. X    register unsigned syze= 0;
  1668. X    *nptrs= 0;
  1669. X    switch (type) {
  1670. X    case Tex: syze= (len+1)*sizeof(char); *nptrs= 0; break;
  1671. X    case ELT:
  1672. X    case Lis:
  1673. X    case Ran:
  1674. X    case Tab: syze= Len*sizeof(value); *nptrs= len; break;
  1675. X    }
  1676. X    return syze;
  1677. X}
  1678. X
  1679. XVisible Procedure rel_subvalues(v) value v; {
  1680. X    rrelease(v);
  1681. X}
  1682. X
  1683. X#define INCOMP    MESS(500, "incompatible types %s and %s")
  1684. X
  1685. XHidden Procedure incompatible(v, w) value v, w; {
  1686. X    value m1, m2, m3, m;
  1687. X    string s1, s2;
  1688. X    
  1689. X    m1= convert(m3= (value) valtype(v), No, No); release(m3);
  1690. X    m2= convert(m3= (value) valtype(w), No, No); release(m3);
  1691. X    s1= sstrval(m1);
  1692. X    s2= sstrval(m2);
  1693. X    sprintf(messbuf, getmess(INCOMP), s1, s2);
  1694. X    m= mk_text(messbuf);
  1695. X    interrV(-1, m);
  1696. X
  1697. X    fstrval(s1); fstrval(s2);
  1698. X    release(m1); release(m2);
  1699. X    release(m);
  1700. X}
  1701. X
  1702. XVisible bool comp_ok;
  1703. X
  1704. X#define Sgn(d) (d)
  1705. X
  1706. XVisible relation compare(v, w) value v, w; {
  1707. X    literal vt= Type(v), wt= Type(w);
  1708. X    register intlet vlen, wlen, len, k;
  1709. X
  1710. X    comp_ok= Yes;
  1711. X    vlen= IsSmallInt(v) ? 0 : Length(v);
  1712. X    wlen= IsSmallInt(w) ? 0 : Length(w);
  1713. X    if (v == w) return 0;
  1714. X    if (!(vt == wt && !(vt == Com && vlen != wlen) ||
  1715. X                vt == Ran && (wt == Lis || wt == ELT) ||
  1716. X                wt == Ran && (vt == Lis || vt == ELT) ||
  1717. X                vt == ELT && (wt == Lis || wt == Tab) ||
  1718. X                wt == ELT && (vt == Lis || vt == Tab))) {
  1719. X        incompatible(v, w);
  1720. X        comp_ok= No;
  1721. X        return -1;
  1722. X    }
  1723. X    if (vt != Num && (vlen == 0 || wlen == 0))
  1724. X        return Sgn(vlen-wlen);
  1725. X    if (vt == Ran || wt == Ran)
  1726. X        return range_comp(v, w);
  1727. X    switch (vt) {
  1728. X    case Num: return numcomp(v, w);
  1729. X    case Tex: return strcmp(Str(v), Str(w));
  1730. X
  1731. X    case Com:
  1732. X    case Lis:
  1733. X    case Tab:
  1734. X    case ELT:
  1735. X        {value *vp= Ats(v), *wp= Ats(w);
  1736. X         relation c;
  1737. X            len= vlen < wlen ? vlen : wlen;
  1738. X            for (k= 0; k < len; k++)
  1739. X                if ((c= compare(*vp++, *wp++)) != 0)
  1740. X                    return c;
  1741. X            return Sgn(vlen-wlen);
  1742. X        }
  1743. X    default:
  1744. X        syserr(MESS(501, "comparison of unknown types"));
  1745. X        /* NOTREACHED */
  1746. X    }
  1747. X}
  1748. X
  1749. XVisible double hash(v) value v; {
  1750. X    if (Is_number(v))
  1751. X        return numhash(v);
  1752. X    else {
  1753. X        literal t= Type(v); intlet len= Length(v), k; 
  1754. X        double d= t+.404*len;
  1755. X        switch (t) {
  1756. X        case Tex:
  1757. X            {string vp= Str(v);
  1758. X                for (k= 0; k < len; k++)
  1759. X                    d= .987*d+.277*(*vp++);
  1760. X                return d;
  1761. X            }
  1762. X        case Com:
  1763. X        case Lis:
  1764. X        case Ran:
  1765. X        case Tab:
  1766. X        case ELT:
  1767. X            {value *vp= Ats(v);
  1768. X                if (len == 0) return .909;
  1769. X                for (k= 0; k < len; k++)
  1770. X                    d= .874*d+.310*hash(*vp++);
  1771. X                return d;
  1772. X            }
  1773. X        default:
  1774. X            syserr(MESS(502, "hash called with unknown type"));
  1775. X            /* NOTREACHED */
  1776. X        }
  1777. X    }
  1778. X}
  1779. X
  1780. X/* For reasons of efficiency, wri does not always call convert but writes
  1781. X   directly on the standard output. Modifications in convert should
  1782. X   be mirrored by changes in wri and vice versa. */
  1783. X
  1784. X#ifdef RANGEPRINT
  1785. XHidden Procedure conc_vals(pt, l, u) value *pt; value l, u; {
  1786. X    value x;
  1787. X    if (compare(l, u) == 0)
  1788. X        concato(pt, x= convert(l, No, No));
  1789. X    else if (is_increment(u, l)) {
  1790. X        concato(pt, x= convert(l, No, No)); release(x);
  1791. X        concato(pt, x= mk_text("; ")); release(x);
  1792. X        concato(pt, x= convert(u, No, No));
  1793. X    }
  1794. X    else {
  1795. X        concato(pt, x= convert(l, No, No)); release(x);
  1796. X        concato(pt, x= mk_text("..")); release(x);
  1797. X        concato(pt, x= convert(u, No, No));
  1798. X    }
  1799. X    release(x);
  1800. X}
  1801. X#endif /* RANGEPRINT */
  1802. X
  1803. X#define Last(k, len)    ((k) == (len)-1)
  1804. X
  1805. XVisible value convert(v, coll, outer) value v; bool coll, outer; {
  1806. X    value t, quote, c, cv, sep, th, open, close, i, s;
  1807. X    int k, len; char ch; relation r;
  1808. X    switch (Type(v)) {
  1809. X    case Num:
  1810. X        return mk_text(convnum(v));
  1811. X    case Tex:
  1812. X        if (outer) return copy(v);
  1813. X        quote= mk_text("\"");
  1814. X        len= length(v);
  1815. X        t= copy(quote);
  1816. X        for (k=1; k<=len; k++) {
  1817. X            c= thof(k, v);
  1818. X            ch= charval(c);
  1819. X            concato(&t, c);
  1820. X            if (ch == '"' || ch == '`') concato(&t, c);
  1821. X            release(c);
  1822. X        }
  1823. X        concato(&t, quote);
  1824. X        release(quote);
  1825. X        break;
  1826. X    case Com:
  1827. X        len= Nfields(v);
  1828. X        outer&= coll;
  1829. X        sep= mk_text(outer ? " " : ", ");
  1830. X        t= mk_text(coll ? "" : "(");
  1831. X        for (k= 0; k < len; k++) {
  1832. X            concato(&t, cv= convert(*Field(v, k), No, outer));
  1833. X            release(cv);
  1834. X            if (!Last(k, len)) concato(&t, sep);
  1835. X        }
  1836. X        release(sep);
  1837. X        if (!coll) {
  1838. X            concato(&t, cv= mk_text(")"));
  1839. X            release(cv);
  1840. X        }
  1841. X        break;
  1842. X    case Ran:
  1843. X    case Lis:
  1844. X    case ELT:
  1845. X        t= mk_text("{");
  1846. X        sep= mk_text("; ");
  1847. X#ifndef RANGEPRINT
  1848. X        i= copy(one); s= size(v); 
  1849. X        while ((r=numcomp(i, s)) <= 0) {
  1850. X            th= item(v, i);
  1851. X            concato(&t, cv= convert(th, No, No));
  1852. X            if (r < 0) {
  1853. X                concato(&t, sep);
  1854. X            }
  1855. X            release(cv); release(th);
  1856. X            i= sum(th=i, one);
  1857. X            release(th);
  1858. X        }
  1859. X        release(i); release(s);
  1860. X#else /* RANGEPRINT */
  1861. X        {
  1862. X            value lwb, upb;
  1863. X            bool first= Yes;
  1864. X            i= copy(one); s= size(v);
  1865. X            while (numcomp(i, s) <= 0) {
  1866. X                th= item(v, i);
  1867. X                if (first) {
  1868. X                    lwb= copy(th);
  1869. X                    upb= copy(th);
  1870. X                    first= No;
  1871. X                }
  1872. X                else if (is_increment(th, upb)) {
  1873. X                    release(upb);
  1874. X                    upb= copy(th);
  1875. X                }
  1876. X                else {
  1877. X                    conc_vals(&t, lwb, upb) ;
  1878. X                    concato(&t, sep);
  1879. X                    release(lwb); release(upb);
  1880. X                    lwb= copy(th); upb= copy(th);
  1881. X                }
  1882. X                release(th);
  1883. X                i= sum(th=i, one);
  1884. X                release(th);
  1885. X            }
  1886. X            if (!first) {
  1887. X                conc_vals(&t, lwb, upb);
  1888. X                release(lwb); release(upb);
  1889. X            }
  1890. X            release(i); release(s);
  1891. X        }
  1892. X#endif /* RANGEPRINT */
  1893. X        concato(&t, cv= mk_text("}"));
  1894. X        release(cv); release(sep);
  1895. X        break;
  1896. X    case Tab:
  1897. X        len= length(v);
  1898. X        open= mk_text("[");
  1899. X        close= mk_text("]: ");
  1900. X        sep= mk_text("; ");
  1901. X        t= mk_text("{");
  1902. X        for (k= 0; k < len; k++) {
  1903. X            concato(&t, open);
  1904. X            concato(&t, cv= convert(*key(v, k), Yes, No));
  1905. X            release(cv);
  1906. X            concato(&t, close);
  1907. X            concato(&t, cv= convert(*assoc(v, k), No, No));
  1908. X            release(cv);
  1909. X            if (!Last(k, len)) concato(&t, sep);
  1910. X        }
  1911. X        concato(&t, cv= mk_text("}")); release(cv);
  1912. X        release(open); release(close); release(sep);
  1913. X        break;
  1914. X    default:
  1915. X        syserr(MESS(503, "unknown type in convert"));
  1916. X    }
  1917. X    return t;
  1918. X}
  1919. X
  1920. X#define Left 'L'
  1921. X#define Right 'R'
  1922. X#define Centre 'C'
  1923. X
  1924. X#define ADJLEFT_NUM    MESS(504, "in t<<n, n is not a number")
  1925. X#define ADJRIGHT_NUM    MESS(505, "in t><n, n is not a number")
  1926. X#define CENTRE_NUM    MESS(506, "in t>>n, n is not a number")
  1927. X
  1928. XHidden value adj(x, y, side) value x, y; literal side; {
  1929. X    value r, v= convert(x, Yes, Yes); int i;
  1930. X    intlet lv, la, k, ls, rs;
  1931. X    string rp, vp;
  1932. X
  1933. X    if (!Is_number(y)) {
  1934. X        switch (side) {
  1935. X        case Left:    interr(ADJLEFT_NUM); break;
  1936. X        case Centre:    interr(ADJRIGHT_NUM); break;
  1937. X        case Right:    interr(CENTRE_NUM); break;
  1938. X        }
  1939. X        return v;
  1940. X    }
  1941. X    i= intval(y);
  1942. X    lv= Length(v);
  1943. X    la= propintlet(i) - lv;
  1944. X    if (la <= 0) return v;
  1945. X    r= grab(Tex, lv+la); rp= Str(r); vp= Str(v);
  1946. X
  1947. X    if (side == Left) { ls= 0; rs= la; }
  1948. X    else if (side == Centre) { ls= la/2; rs= (la+1)/2; }
  1949. X    else { ls= la; rs= 0; }
  1950. X
  1951. X    for (k= 0; k < ls; k++) *rp++= ' ';
  1952. X    for (k= 0; k < lv; k++) *rp++= *vp++;
  1953. X    for (k= 0; k < rs; k++) *rp++= ' ';
  1954. X    *rp= 0;
  1955. X    release(v);
  1956. X    return r;
  1957. X}
  1958. X
  1959. XVisible value adjleft(x, y) value x, y; {
  1960. X    return adj(x, y, Left);
  1961. X}
  1962. X
  1963. XVisible value centre(x, y) value x, y; {
  1964. X    return adj(x, y, Centre);
  1965. X}
  1966. X
  1967. XVisible value adjright(x, y) value x, y; {
  1968. X    return adj(x, y, Right);
  1969. X}
  1970. X
  1971. X
  1972. END_OF_FILE
  1973.   if test 7180 -ne `wc -c <'abc/lin/i1obj.c'`; then
  1974.     echo shar: \"'abc/lin/i1obj.c'\" unpacked with wrong size!
  1975.   fi
  1976.   # end of 'abc/lin/i1obj.c'
  1977. fi
  1978. if test ! -d 'abc/scripts' ; then
  1979.     echo shar: Creating directory \"'abc/scripts'\"
  1980.     mkdir 'abc/scripts'
  1981. fi
  1982. if test ! -d 'abc/stc' ; then
  1983.     echo shar: Creating directory \"'abc/stc'\"
  1984.     mkdir 'abc/stc'
  1985. fi
  1986. if test ! -d 'abc/tc' ; then
  1987.     echo shar: Creating directory \"'abc/tc'\"
  1988.     mkdir 'abc/tc'
  1989. fi
  1990. if test ! -d 'abc/uhdrs' ; then
  1991.     echo shar: Creating directory \"'abc/uhdrs'\"
  1992.     mkdir 'abc/uhdrs'
  1993. fi
  1994. if test ! -d 'abc/ukeys' ; then
  1995.     echo shar: Creating directory \"'abc/ukeys'\"
  1996.     mkdir 'abc/ukeys'
  1997. fi
  1998. if test ! -d 'abc/unix' ; then
  1999.     echo shar: Creating directory \"'abc/unix'\"
  2000.     mkdir 'abc/unix'
  2001. fi
  2002. echo shar: End of archive 1 \(of 25\).
  2003. cp /dev/null ark1isdone
  2004. MISSING=""
  2005. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ; do
  2006.     if test ! -f ark${I}isdone ; then
  2007.     MISSING="${MISSING} ${I}"
  2008.     fi
  2009. done
  2010. if test "${MISSING}" = "" ; then
  2011.     echo You have unpacked all 25 archives.
  2012.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2013. else
  2014.     echo You still must unpack the following archives:
  2015.     echo "        " ${MISSING}
  2016. fi
  2017. exit 0
  2018.